﻿#include <utils/ThreadPool.h>
#include <Common.h>

#define TAG "THREAD_POOL"

// 必须在类外初始化
ThreadPool* ThreadPool::singleton = nullptr;

ThreadPool::ThreadPool()
{
	_isPoolRunning = false;

	_coreThreadSize = THREAED_CORE_THRESHHOLD;
	_curThreadSize = 0;
	_threadMaxThreshHold = THREAED_MAX_THRESHHOLD;
	_taskSize = 0;
	_taskQueMaxThreshHold = TASK_MAX_THRESHHOLD;
	_poolMode = ThreadPoolMode::ThreadPoolModeCACHED;
	_idleThreadSize = 0;
}

ThreadPool::~ThreadPool()
{
	exit();
}

void ThreadPool::threadFunc(int threadid)
{
	// 获取一个高精度时间
	auto lastTime = std::chrono::high_resolution_clock().now();
	while (_isPoolRunning)
	{
		Task task;
		{
			// 先获取锁
			std::unique_lock<std::mutex> lock(_taskQueMtx);
			//std::cout << "tid: " << std::this_thread::get_id() << " 尝试获取任务..." << std::endl;

			// cache模式下，有可能已经创建了很多的线程，但是空闲时间超过60s，应该把多余的线程给取消了
			// 当前时间 - 上一次线程执行时间 > 60s
			// 等待nonEmpty
			// 总结：也就是线程获取任务的过程中等待过长时间就可以进行删除


			// 每1s返回一次，区分 超时返回？有任务待执行
			while (_taskSize <= 0)
			{
				// 条件变量，超时返回
				if (_poolMode == ThreadPoolMode::ThreadPoolModeCACHED)
				{
					if (std::cv_status::timeout == _nonEmpty.wait_for(lock, std::chrono::seconds(1)))
					{
						auto now = std::chrono::high_resolution_clock().now();
						auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
						if (dur.count() >= THREAD_MAX_IDLE_TIME
							&& _curThreadSize > _coreThreadSize)
						{
							// 开始回收当前线程
							// 记录线程数量的相关变量的值修改
							// 把线程对象从线程列表容器中删除 到那时没有办法直到对应的thread的线程对象
							// threadid => thread对象 
							_threads.erase(threadid);// 删除id，不能用this_thread里面的id
							_curThreadSize--;
							_idleThreadSize--;
							LogD("threadid exit!");
							return;
						}
					}
				}
				else
				{
					_nonEmpty.wait(lock);
				}
				// 线程等待被唤醒后，两种情况都检查是被谁唤醒
				// 线程池要结束，回收线程资源
				if (!_isPoolRunning)
				{
					// erase就是调用了unique_ptr的析构函数，会把Thread删除，这里就已经删除线程了
					_threads.erase(threadid);// 删除id，不能用this_thread里面的id
					LogD("threadid exit!");
					_exitCond.notify_all();
					return;
				}
			}
			_taskSize--;
			// 取任务
			//是不是这里取任务有问题,加了打印就正常,概率性的,没有锁在加减任务的时候就会有问题
			//std::cout << "tid: " << std::this_thread::get_id() << " 获取任务成功" << std::endl;
			task = _taskQue.front();
			_taskQue.pop();

			// 如果依然有剩余的任务，继续通知其他线程执行任务
			if (_taskQue.size() > 0)
			{// 第一个吃螃蟹的通知其他人吃螃蟹
				_nonEmpty.notify_all();
			}
			// 取出一个任务，进行通知，通知可以继续提交生产任务
			_notFull.notify_all();
			_idleThreadSize--;
		}

		// 释放锁,执行任务
		if (task != nullptr)
		{
			// task->run();
			// 执行任务：把任务的返回值通过setVal方法给到Result
			//task->exec();
			task(); // 执行package_task封装的函数，执行完会post
		}
		{
			std::unique_lock<std::mutex> lock(_taskQueMtx);
			// 返回值处理
			_idleThreadSize++;// 线程执行完了任务，空闲线程++
		}
		

		// 更新线程调度执行完任务的时间
		lastTime = std::chrono::high_resolution_clock().now();
	}
	// isRunLooping_表示部分线程在线程池要退出的时候刚好在执行任务，执行后到这里
	_threads.erase(threadid);// 删除id，不能用this_thread里面的id
	LogD("threadid exit!");
	_exitCond.notify_all();
}


ThreadPool* ThreadPool::getInstance()
{
    if (ThreadPool::singleton == nullptr) {
        singleton = new ThreadPool();
    }
    return singleton;  
}

bool ThreadPool::getPoolState()
{
	return _isPoolRunning;
}

ThreadPoolMode ThreadPool::getThreadPoolMode() const
{
	return _poolMode;
}

void ThreadPool::setThreadPoolMode(ThreadPoolMode mode)
{
	if (!_isPoolRunning) {
		_poolMode = mode;
	}
}

void ThreadPool::setThreadMaxThreshHold(int threshhold)
{
	if (!_isPoolRunning && _poolMode == ThreadPoolMode::ThreadPoolModeCACHED && threshhold > _coreThreadSize) {
		_threadMaxThreshHold = threshhold;
	}
}

int ThreadPool::getThreadMaxThreshHold()const
{
	return _threadMaxThreshHold;
}

void ThreadPool::setTaskQueMaxThreshHold(int threshhold)
{
	_taskQueMaxThreshHold = threshhold;
}

int ThreadPool::getTaskQueMaxThreshHold()const
{
	return _taskQueMaxThreshHold;
}

int ThreadPool::getCoreThreadSize()const
{
	return _coreThreadSize;
}

int ThreadPool::getCurThreadSize()const
{
	return _curThreadSize;
}

int ThreadPool::getIdleThreadSize()const
{
	return _idleThreadSize;
}

int ThreadPool::getTaskSize() const
{
	return _taskSize;
}

bool ThreadPool::taskIsFull() const
{
	return  _taskQue.size() >= _taskQueMaxThreshHold;;
}

void ThreadPool::start()
{
	// 设置线程池的运行状态
	_isPoolRunning = true;
	// 记录初始线程的个数
	_curThreadSize = _coreThreadSize;

	// 创建线程对象
	for (int i = 0; i < _coreThreadSize; ++i)
	{
		// 这里把线程函数传递给线程
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));
		int threadId = ptr->getId();
		_threads.emplace(threadId, std::move(ptr));
		/*threads_.emplace_back(std::move(ptr));*/
	}

	// 启动所有线程
	for (int i = 0; i < _coreThreadSize; ++i)
	{
		// 创建线程，启动线程，执行线程函数：即查看任务队列是否有任务，若有就拿走执行
		_threads[i]->start();;
		_idleThreadSize++; // 记录初始空闲线程的数量
	}
	LogD("core:"<< _coreThreadSize<<" idleThreadSize:"<< _idleThreadSize);
}

void ThreadPool::exit()
{
	_isPoolRunning = false;

	// 等待线程池里面所有的线程返回，有两种状态： 阻塞 & 正在执行的任务
	std::unique_lock<std::mutex> lock{ _taskQueMtx };
	_nonEmpty.notify_all();// 唤醒所有的线程
	// 所有线程都释放，这里才会彻底退出
	_exitCond.wait(lock, [&]()->bool {return _threads.size() == 0; });
}

